/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.atteo.moonshine.firebuglogger; import java.io.IOException; import java.io.StringWriter; import javax.servlet.http.HttpServletResponse; import org.codehaus.jackson.JsonFactory; import org.codehaus.jackson.JsonGenerator; import ch.qos.logback.classic.PatternLayout; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.Context; import ch.qos.logback.core.UnsynchronizedAppenderBase; public class FireBugAppender extends UnsynchronizedAppenderBase<ILoggingEvent> { private static ThreadLocal<HttpServletResponse> response = new ThreadLocal<>(); private static ThreadLocal<Integer> headerNumber = new ThreadLocal<>(); private PatternLayout layout; public FireBugAppender() { layout = new PatternLayout(); layout.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"); } @Override public void setContext(Context context) { super.setContext(context); layout.setContext(context); } @Override public void start() { super.start(); layout.start(); } public static void setServletResponse(HttpServletResponse resp) { response.set(resp); headerNumber.set(0); } @Override protected void append(ILoggingEvent event) { if (response.get() == null) { return; } event.prepareForDeferredProcessing(); String message = layout.doLayout(event); String filename = null; Integer line = null; if (event.hasCallerData()) { StackTraceElement callerData = event.getCallerData()[0]; filename = callerData.getFileName(); line = callerData.getLineNumber(); } StringWriter writer = new StringWriter(); try { JsonGenerator builder = new JsonFactory().createJsonGenerator(writer); builder.writeStartArray(); builder.writeStartObject(); builder.writeFieldName("Type"); builder.writeString(event.getLevel().toString()); builder.writeFieldName("File"); if (filename != null) { builder.writeString(filename); } else { builder.writeNull(); } builder.writeFieldName("Line"); if (line != null) { builder.writeNumber(line); } else { builder.writeNull(); } builder.writeFieldName("Label"); builder.writeString("[S]"); builder.writeEndObject(); builder.writeString(message); builder.writeEndArray(); builder.flush(); } catch (IOException e) { throw new RuntimeException(e); } HttpServletResponse resp = response.get(); resp.setHeader("X-Wf-Protocol-1", "http://meta.wildfirehq.org/Protocol/JsonStream/0.2"); resp.setHeader("X-Wf-1-Plugin-1", "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3"); resp.setHeader("X-Wf-1-Structure-1", "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1"); int number = headerNumber.get(); int offset = 0; int size = writer.getBuffer().length(); while (size > offset) { StringBuilder header = new StringBuilder(); if (offset == 0) { header.append(size); } header.append("|"); int end = offset + 4000; if (end > size) { end = size; } header.append(writer.getBuffer().substring(offset, end)); header.append("|"); offset = end; if (offset != size) { header.append("\\"); } resp.setHeader("X-Wf-1-1-1-" + number, header.toString()); number++; } headerNumber.set(number); } }